Introduction

Functions are an essential part of programming in C++ and any C-like languages. You will be using them throughout your time with the language, and it is important to know how to design, write, and implement them well.

Function Design

A function should accomplish one, and only one, task. The function might do that task many times, or in many different situations, but the function should only be designed to solve one type of problem. The scope of that problem is up to you, as is where you want to break parts of that task into sub-tasks for other functions. In general, you should not have separate types of operations, say data processing and console output, in the same function.

For example, the main function always has the task of executing your program. A function you create might display a menu system, and another might execute a selection, and another might do something specific within that option, etc.

Furthermore, functions should always demonstrate modularity and re-usability. A function is essentially a reusable block of code, and you should use it like one—if there is logic in your program that you are using or may use multiple times, it should be broken out into a reusable function. It is, of course, useful to have re-usable logic, but it is even more useful if that logic can be generalized to work in many different situations. This is modularity—you should be able to not only re-use a modular function, but apply it to new situations as well. For example, a reusable function might output the score of player one, whereas a reusable and modular function might output the score of any specified player.

Finally, functions should, of course, meet their specifications. This simply means that the function should do what you intend it to do, and nothing more. Pretty self-explanatory.

Declaring Functions

Now that you know what functions do, you're probably wondering how to use them. There are several important aspects of functions that you need to be familiar with in order to use them effectively.

You've already seen the basic structure of a function—"main" in your previous programs. At its core, a function is simply a block of code that can be called from elsewhere, optionally receiving and manipulating data.

To declare a function in C or C++, there are two things you have to do. First, there is the function prototype, which goes at the top of your program, before your main function. The prototype is technically unnecessary, as you could simply write out (implement) your entire function there instead. However, when the compiler is looking at a line of code, it can only see above it—what if you wanted to call another function you wrote, which is below? What if that function wants to call the upper function? Your program wouldn't compile.

What the prototype does is describe to the compiler what functions will be implemented at some point, and allows the rest of your program to automatically use them. If you don't create prototypes, it can lead to a lot of headaches. The basic structure of a prototype is:

<data type> functionName(<data type> parameter1, <data type> parameter2, ...);

There are several components to this statement. First, the leftmost data type describes what type of data the function will return. More on that under using functions. If you don't want your function to return any data, you can use "void" instead of a data type such as "int" or "double." Second, there is your function identifier, which you will use to refer to your function in the future (see lesson 01). Finally, you have your function's parameters enclosed in parenthesis. Parameters describe the data your function will receive when it is called by other code. To describe a parameter, first type the data type of the parameter, for example "int" or "char," and second the identifier of the parameter. This will be how you refer to the parameter within the function. To add more parameters, simply add a comma and repeat the process. The parameters specified here in the prototype are called formal parameters, as they define the structure of the function and how the data will be refereed to within the function.

Of course, don't forget to end your prototype with a semicolon.

void printCharacters(int numCharacters, char character);
double calcRoot(int a, int b, int c);

Implementing Functions

One you have written your function prototype, you can move on to implementing the actual function. To begin the implementation of a function, simply copy and paste your prototype—minus the semicolon—below your main function, and add a pair of curly brackets. Here, you will write the code of your function. While writing your function, your parameters are available for use like any other variables. They will hold the data passed into the function when it is called—again, more on that under using functions. At some point in your function (usually the end), you must put a "return" statement. This describes what data you want to send back from your function. The "returned" data must have the same type as you described in your prototype. The "return" statement must always be run at some point in your function, unless you specified your return type as "void"—in which case you must leave out the return statement entirely.

As for syntax—after the keyword return, you may specify either a literal value or much more commonly a variable (whose type is the same as the return type) that has been computed by your function.

double calcRoot(int a, int b, int c) {
	double x;
	x = (-b + sqrt(b*b – 4*a*c)) / 2*a;
	return x;
}

Using Functions

Finally, you need to learn how to use your new function. Using your function elsewhere in your program is called calling, or invoking, the function. To do so, simply type the identifier of your function. Then, add parenthesis and specify the "actual" parameters. They represent the actual data that you pass to the function when it is called—the data you pass here will be copied to your parameters within your function. You can pass literal values or variables. Your data must match the types specified in the prototype, but know that your actual parameters do not need to have the same name as your formal parameters. This means that if you have a parameter named "value_one" of type "double", you can pass in a variable named "input," so long as it is also of type double.

Whether or not your function returns a value, that's all you need to do. However, if your function returns a value that you care about, you can capture the value using the assignment operator (=). Simply put the function call on the right and a variable matching the return type on the left. This means if your function returns an int, you must receive the returned data in a variable of type int.

double result;
int value_a = 5;
int value_b = 3;

result = calcRoot(value_a, value_b, 12);

Here, you can see the use of two variables as parameters, a literal as a parameter, and a captured return value.

Default Parameters

When you define parameters for your function (in the function prototype), you can set one or more equal to a value. This will create a default parameter, which means that the parameter does not require a value when the function is called. Data can still be passed in like with a normal parameter, but if it’s not, the value will simply have the default you specified for it. All default parameters must come after the required parameters, because if they are in the middle, the complier will not know if you want to pass the required or default parameter. Furthermore, if your function has multiple default parameters, you must send data to them in the order they are described—again, where you want your data to go would otherwise be arbitrary

// Prototype
int function(int x, int y, int var = 5);

// Implementation
int function(int x, int y, int var) {
	return (x + y) / var;
}

int int1 = function(3,7);		// This is valid, and will return the value 2
int int3 = function(3,7,2);		// This is also valid, and will return the value 5

Overloading Functions

C and C++ support overloaded functions. Essentially, this means that you can have multiple functions with the same name. However, all functions must have different signatures. A function's signature is the combination of its identifier and parameter types. Hence, if you create multiple functions with the same identifier, they must have different parameter types. For example, you can create several print() functions, each which takes a different data type parameter. Of course, you could instead create printInt, printDbl, etc...function overloading is only required in one situation (see lesson 13), but can be useful for style and API design, especially if you do not want to use templates.

void func(int x, int y, int z) {

}

void func(float x, float y, float z) {
	
}

void func(coord c) {
	
}

int main() {
	func(5,4,6); 			// Calls the first overload
	func(5.0f,4.0f,6.0f); 		// Calls the second overload
	func(coord(5,4,6)); 		// Calls the third overload
}

Note that the parameter identifiers do not affect a function's signature. This means that print(int x) and print(int y) have the same signature, and will produce an error if both implemented. To overload a function, you must use a different combination of parameter data types. This makes sense—when you call an overloaded function, the only way your program knows which function to call is by deducing the parameter types.

Static Variables

Static variables are essentially scoped global variables. While they can only be used within the scope they are declared in, they retain their value even after the scope ends. This means that you can declare a static variable in a function or loop, and have it keep track of a value throughout the program's lifetime. For example, you could have a function keep track of how many times it has been run, and do something different every 10th time. Because a static variable is persistent, the line declaring it is only run once. Hence, you can set it to a default value on declaration.

The syntax is very simple: just add the keyword "static" before your variable declaration.

for(int i = 0; i < 10; i++) {
	for(int j = 0; j < 10; j++) {
		static int counter = 0;
		counter++;
	}
}
void func() {
	static int timesRun = 0;
	// ...
	timesRun++;
}

Programming Exercises

  1. Create a program, using functions for each of the main tasks. The program should prompt the user for information, process the data, and display the result.
  2. Create some of your own functions. Try out using different return types (such as void), as well as different combinations of parameters.
  3. Try removing the prototypes from the example program and see what can do to fix the error, other than putting the prototypes back in.